libostree: Add some additional metadata to the summary file
authorPhilip Withnall <withnall@endlessm.com>
Tue, 2 May 2017 21:22:15 +0000 (22:22 +0100)
committerAtomic Bot <atomic-devel@projectatomic.io>
Mon, 8 May 2017 00:55:24 +0000 (00:55 +0000)
 • Commit timestamps, so it’s easy to work out whether a given commit is
   newer than the one we have locally
 • Summary file timestamp, so it’s easy to work out whether the summary
   file is more up to date than another summary file
 • Summary file expiry time, so clients can work out when they should
   expect the summary file to next be updated, and hence can query for
   it at roughly the right time

The expiry time requires input from the user, so is currently never set
automatically. Programs using libostree can set it if they wish.

Signed-off-by: Philip Withnall <withnall@endlessm.com>
Closes: #826
Approved by: cgwalters

src/libostree/ostree-core.h
src/libostree/ostree-repo-private.h
src/libostree/ostree-repo.c

index b25112db7518c56963a3064e159e57c8e654a54a..59d6d9e25326675b4c98778af20de34dc1f10e89 100644 (file)
@@ -158,6 +158,17 @@ typedef enum {
  * - a(s(taya{sv})) - Map of ref name -> (latest commit size, latest commit checksum, additional metadata), sorted by ref name
  * - a{sv} - Additional metadata, at the current time the following are defined:
  *   - key: "ostree.static-deltas", value: a{sv}, static delta name -> 32 bytes of checksum
+ *   - key: "ostree.summary.last-modified", value: t, timestamp (seconds since
+ *     the Unix epoch in UTC, big-endian) when the summary was last regenerated
+ *     (similar to the HTTP `Last-Modified` header)
+ *   - key: "ostree.summary.expires", value: t, timestamp (seconds since the
+ *     Unix epoch in UTC, big-endian) after which the summary is considered
+ *     stale and should be re-downloaded if possible (similar to the HTTP
+ *     `Expires` header)
+ *
+ * The currently defined keys for the `a{sv}` of additional metadata for each commit are:
+ *  - key: `ostree.commit.timestamp`, value: `t`, timestamp (seconds since the
+ *    Unix epoch in UTC, big-endian) when the commit was committed
  */
 #define OSTREE_SUMMARY_GVARIANT_STRING "(a(s(taya{sv}))a{sv})"
 #define OSTREE_SUMMARY_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_SUMMARY_GVARIANT_STRING)
index 94330226b33074fa0e541159cb27211f43165bc2..87e67a237e60fad4c865525487865df18fc5b1c2 100644 (file)
@@ -43,6 +43,14 @@ G_BEGIN_DECLS
  * */
 #define _OSTREE_MAX_OUTSTANDING_WRITE_REQUESTS 16
 
+/* Well-known keys for the additional metadata field in a summary file. */
+#define OSTREE_SUMMARY_LAST_MODIFIED "ostree.summary.last-modified"
+#define OSTREE_SUMMARY_EXPIRES "ostree.summary.expires"
+
+/* Well-known keys for the additional metadata field in a commit in a ref entry
+ * in a summary file. */
+#define OSTREE_COMMIT_TIMESTAMP "ostree.commit.timestamp"
+
 typedef enum {
   OSTREE_REPO_TEST_ERROR_PRE_COMMIT = (1 << 0)
 } OstreeRepoTestErrorFlags;
index e204fd15e0b7211bdc9efb07542f8ca4e461ed06..fd7aa55d14c15c04eb9d9457f35de797025c6339 100644 (file)
@@ -4563,6 +4563,10 @@ ostree_repo_verify_summary (OstreeRepo    *self,
  * An OSTree repository can contain a high level "summary" file that
  * describes the available branches and other metadata.
  *
+ * If the timetable for making commits and updating the summary file is fairly
+ * regular, setting the `ostree.summary.expires` key in @additional_metadata
+ * will aid clients in working out when to check for updates.
+ *
  * It is regenerated automatically after a commit if
  * `core/commit-update-summary` is set.
  */
@@ -4595,6 +4599,9 @@ ostree_repo_regenerate_summary (OstreeRepo     *self,
       const char *commit = g_hash_table_lookup (refs, ref);
       g_autofree char *remotename = NULL;
       g_autoptr(GVariant) commit_obj = NULL;
+      g_auto(GVariantDict) commit_metadata_builder = OT_VARIANT_BUILDER_INITIALIZER;
+      guint64 commit_timestamp;
+      g_autoptr(GDateTime) dt = NULL;
 
       g_assert (commit);
 
@@ -4608,11 +4615,21 @@ ostree_repo_regenerate_summary (OstreeRepo     *self,
       if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, commit, &commit_obj, error))
         goto out;
 
-      g_variant_builder_add_value (refs_builder, 
+      g_variant_dict_init (&commit_metadata_builder, NULL);
+
+      /* Forward the commit’s timestamp if it’s valid. */
+      commit_timestamp = ostree_commit_get_timestamp (commit_obj);
+      dt = g_date_time_new_from_unix_utc (commit_timestamp);
+
+      if (dt != NULL)
+        g_variant_dict_insert_value (&commit_metadata_builder, OSTREE_COMMIT_TIMESTAMP,
+                                     g_variant_new_uint64 (GUINT64_TO_BE (commit_timestamp)));
+
+      g_variant_builder_add_value (refs_builder,
                                    g_variant_new ("(s(t@ay@a{sv}))", ref,
                                                   (guint64) g_variant_get_size (commit_obj),
                                                   ostree_checksum_to_bytes_v (commit),
-                                                  ot_gvariant_new_empty_string_dict ()));
+                                                  g_variant_dict_end (&commit_metadata_builder)));
     }
 
 
@@ -4661,6 +4678,11 @@ ostree_repo_regenerate_summary (OstreeRepo     *self,
     g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_STATIC_DELTAS, g_variant_dict_end (&deltas_builder));
   }
 
+  {
+    g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_LAST_MODIFIED,
+                                 g_variant_new_uint64 (GUINT64_TO_BE (g_get_real_time () / G_USEC_PER_SEC)));
+  }
+
   {
     g_autoptr(GVariantBuilder) summary_builder =
       g_variant_builder_new (OSTREE_SUMMARY_GVARIANT_FORMAT);